﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Xml;
using DotNetNuke.Framework;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Users;
using DotNetNuke.Entities.Profile;
using DotNetNuke.Framework.JavaScriptLibraries;
using DotNetNuke.Security.Roles;
using DotNetNuke.Security.Membership;
using DotNetNuke.Services.Localization;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.FileSystem;
using DotNetNuke.UI.Skins;
using DotNetNuke.UI.Skins.Controls;
using DotNetNuke.UI.WebControls;
using DotNetNuke.Security.Permissions;

namespace WESNet.DNN.Modules.UserExport
{
    public partial class UserExport : PortalModuleBase
    {

#region Member Fields

        private bool? _IsAdministrator;
        private bool? _IsSuperUser;
        private int? _SelectedPortalId;

        private string _RootDirectoryMapPath;
        private string _LocalizedRootFolder;
        private Dictionary<int, ProfileProperty> _ProfileProperties;

#endregion


            
#region Private Properties

        private bool IsAdministrator
        {
            get
            {
                if (!_IsAdministrator.HasValue)
                {
                    _IsAdministrator = (UserInfo.IsInRole("Administrators") || UserInfo.IsSuperUser);
                }
                return (bool)_IsAdministrator;
            }
        }

        private bool IsSuperUser
        {
            get
            {
                if (!_IsSuperUser.HasValue)
                {
                    _IsSuperUser = UserInfo.IsSuperUser;
                }
                return (bool)_IsSuperUser;
            }
        }

        private int SelectedPortalId
        {
            get
            {
                if (!_SelectedPortalId.HasValue)
                {
                    _SelectedPortalId = (IsSuperUser ? Convert.ToInt32(ddlPortal.SelectedValue) : PortalId);
                }
                return (int)_SelectedPortalId;
            }
            set
            {
                _SelectedPortalId = value;
            }
        }

        private DateRange CreatedOnDateRange
        {
            get
            {
                return new DateRange(dpCreatedOnDateStart.SelectedDate, dpCreatedOnDateEnd.SelectedDate);
            }
            set
            {
                dpCreatedOnDateStart.SelectedDate = value.StartDate;
                dpCreatedOnDateEnd.SelectedDate = value.EndDate;
            }
        }

        private DateRange LastLoginDateRange
        {
            get
            {
                return new DateRange(dpLastLoginDateStart.SelectedDate, dpLastLoginDateEnd.SelectedDate);
            }
            set
            {
                dpLastLoginDateStart.SelectedDate = value.StartDate;
                dpLastLoginDateEnd.SelectedDate = value.EndDate;
            }
        }
        
        private string RootDirectoryMapPath
        {
            get
            {
                if (_RootDirectoryMapPath == null)
                {
                    _RootDirectoryMapPath = IsSuperUser ? Globals.HostMapPath : PortalSettings.HomeDirectoryMapPath;
                }
                return _RootDirectoryMapPath;
            }
        }

        private string LocalizedRootFolderName
        {
            get
            {
                if (_LocalizedRootFolder == null)
                {
                    _LocalizedRootFolder = IsSuperUser ? LocalizeString("HostRoot") : LocalizeString("PortalRoot");
                }
                return _LocalizedRootFolder;
            }
        }

        private Dictionary<int, ProfileProperty> ProfileProperties
        {
            get
            {
                if (_ProfileProperties == null)
                {
                    _ProfileProperties = GetProfileProperties(SelectedPortalId);
                }
                return _ProfileProperties;
            }
        }

        private ExportFormats SelectedExportFormat
        {
            get
            {
                return (ExportFormats)Convert.ToInt32(rblExportFormat.SelectedValue);
            }
            set
            {
                rblExportFormat.SelectedValue = value.ToString("d");
            }
        }

        private ExportDestinations SelectedExportDestination
        {
            get
            {
                return (ExportDestinations)Convert.ToInt32(rblExportDestination.SelectedValue);
            }
            set
            {
                rblExportDestination.SelectedValue = value.ToString("d");
            }
        }

        private EmailOptions SelectedEmailOption
        {
            get
            {
                return (EmailOptions)Convert.ToInt32(rblEmailOption.SelectedValue);
            }
            set
            {
                rblEmailOption.SelectedValue = value.ToString("d");
            }
        }

#endregion

#region Event Handlers


        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            JavaScript.RequestRegistration(CommonJs.DnnPlugins);
        }
        
        protected void Page_Load(object sender, EventArgs e)
        {
            grdRolesToExport.LocalResourceFile = LocalResourceFile;
            grdRolesToExclude.LocalResourceFile = LocalResourceFile;
            grdEmailToRoles.LocalResourceFile = LocalResourceFile;

            ddlPortal.SelectedIndexChanged += ddlPortal_SelectedIndexChanged;
            Localization.LocalizeDataGrid(ref grdProfileProperties, LocalResourceFile);
            grdProfileProperties.ItemDataBound += grdProfileProperties_OnItemDatabound;

            cmdExport.Click += cmdExport_Click;
            cmdCancel.Click += cmdCancel_Click;
            
            if(!Page.IsPostBack)
            {
                BindPortals();
                BindRoleGrids();
                SelectedExportFormat = ExportFormats.XML;
                SelectedExportDestination = ExportDestinations.PortalFile;
                SelectedEmailOption = EmailOptions.None;
                tbEmailTo.Text = !String.IsNullOrEmpty(UserInfo.Email) ? UserInfo.Email : PortalSettings.Email;
                BindFolders();
                BindProfileProperties();
            }
        }

        protected void ddlPortal_SelectedIndexChanged(object sender, EventArgs e)
        {
            SelectedPortalId = Convert.ToInt32(ddlPortal.SelectedValue);
            BindRoleGrids();
            InvalidateProfileProperties();
            BindProfileProperties();
        }

        private void BindRoleGrids()
        {
            grdRolesToExport.PortalID = SelectedPortalId;
            grdRolesToExclude.PortalID = SelectedPortalId;
            grdEmailToRoles.PortalID = SelectedPortalId;
        }

        private void grdProfileProperties_OnItemDatabound(object sender, DataGridItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                ProfileProperty pp = (ProfileProperty)e.Item.DataItem;
                if (pp.DefaultVisibility == UserVisibilityMode.AdminOnly && !IsAdministrator)
                {
                    CheckBox cbSelected = (CheckBox)(e.Item.Cells[0].Controls[0]);
                    cbSelected.Checked = false;
                    cbSelected.Enabled = false;
                }
            }
        }

        protected void cmdExport_Click(object sender, EventArgs e)
        {
            try
            {
                List<string> exportRoles = grdRolesToExport.SelectedRoleNames;
                if (exportRoles.Count == 0)
                {
                    ShowModuleMessage(LocalizeString("NoExportRolesSelected"), ModuleMessage.ModuleMessageType.RedError);
                    return;
                }

                List<string> excludeRoles = grdRolesToExclude.SelectedRoleNames;
                if (exportRoles.Intersect(excludeRoles).Count() > 0)
                {
                    ShowModuleMessage(LocalizeString("ExportRolesExcluded"), ModuleMessage.ModuleMessageType.RedError);
                    return;
                }

                Dictionary<int, ProfileProperty> selectedProfileProperties = GetSelectedProfileProperties();
                if (selectedProfileProperties.Count == 0)
                {
                    ShowModuleMessage(LocalizeString("NoProfilePropertiesSelected"), ModuleMessage.ModuleMessageType.RedError);
                    return;
                }

                var exporter = new Exporter(ModuleId, SelectedPortalId, SelectedExportFormat, SelectedExportDestination);
                exporter.LocalResourceFile = LocalResourceFile;
                exporter.ExportRoles = exportRoles;
                exporter.ExcludeRoles = excludeRoles;
                exporter.SelectedProfileProperties = selectedProfileProperties;
                exporter.IncludeUnapproved = cbIncludeUnapproved.Checked;
                exporter.IncludeSoftDeleted = cbIncludeSoftDeleted.Checked;
                exporter.CreatedOnDateRange = CreatedOnDateRange;
                exporter.LastLoginDateRange = LastLoginDateRange;

                exporter.ExportCSVHeaderRow = cbExportCSVHeaderRow.Checked;
                exporter.CSVDelimiter = ddlCSVDelimiter.SelectedValue[0];
                exporter.CSVQuoteValues = cbCSVQuotes.Checked;

                exporter.IncludeUserRoleInformation = cbIncludeUserRoleInformation.Checked;
                exporter.IncludeRelationshipInformation = cbIncludeRelationshipInformation.Checked;
                exporter.ExportXLSHeaderRow = cbExportXLSHeaderRow.Checked;

                exporter.ExportFolderID = Convert.ToInt32(ddlPortalFolder.SelectedValue);
                exporter.ExportFilename = SelectedExportDestination == ExportDestinations.PortalFile ? tbPortalFilename.Text : tbDownloadFileName.Text;
                exporter.ProcessAsynch = cbProcessAsynch.Checked;
                exporter.EmailOption = SelectedEmailOption;
                exporter.EmailTo = tbEmailTo.Text;
                exporter.EmailFrom = UserInfo.Email;
                exporter.EmailToRoles = grdEmailToRoles.SelectedRoleNames;

                exporter.OpenDownloadInNewWindow = cbOpenInNewWindow.Checked;


                exporter.ExportUsers();

                var message = "";
                var exportFailed = false;

                switch (exporter.ExportStatus)
                {
                    case ExportStatuses.ExportSuccess:
                        message = string.Format(LocalizeString("ExportSuccess"), exporter.ExportFilepath, exporter.ExportedCount, exporter.SkippedCount);
                        break;
                    case ExportStatuses.AsynchExportStarted:
                        message = string.Format(LocalizeString("AsynchExportStarted"), exporter.ExportFilepath);
                        break;
                    default:
                        exportFailed = true;
                        message = LocalizeString("ExportFailure") + "<br />";
                        foreach (string exporterMessage in exporter.ExporterMessages)
                        {
                            message += "<br />" + exporterMessage;
                        }
                        break;
                }
                ShowModuleMessage(message, exportFailed ? ModuleMessage.ModuleMessageType.RedError : ModuleMessage.ModuleMessageType.GreenSuccess);
            }
            catch (Exception exc)
            {
                DotNetNuke.Services.Exceptions.Exceptions.ProcessModuleLoadException(exc.Message, this, exc, true);
            }
        }        

        protected void cmdCancel_Click (object sender, EventArgs e)
        {
            Response.Redirect(DotNetNuke.Common.Globals.NavigateURL(), true);
        }

#endregion

#region Protected and Public Utility Methods

        protected new string LocalizeString(string resourceKey)
        {
            return Localization.GetString(resourceKey, LocalResourceFile);
        }

#endregion
        
#region Private Utility Methods

        private List<string> GetSelectedRoleNames (DotNetNuke.UI.WebControls.RolesSelectionGrid grd)
        {
            return grd.SelectedRoleNames.Cast<string>().ToList<string>();
        }     

        private void InvalidateProfileProperties()
        {
            _ProfileProperties = null;
        }

        private void BindPortals()
        {
            var pc = new PortalController();
            ArrayList portals = pc.GetPortals();
            ddlPortal.DataSource = portals;
            ddlPortal.DataBind();
            ddlPortal.SelectedValue = PortalId.ToString();
            divPortal.Visible = (IsSuperUser && ddlPortal.Items.Count > 1);
        }

        private void BindFolders()
        {
            var folders = FolderManager.Instance.GetFolders(-1, "READ, WRITE", UserInfo.UserID);

            foreach (FolderInfo folder in folders)
            {
                ddlPortalFolder.Items.Add(new ListItem((folder.FolderPath == "" ? LocalizedRootFolderName : folder.FolderPath), folder.FolderID.ToString()));
            }

            if (ddlPortalFolder.Items.Count > 0)
            {
                ddlPortalFolder.SelectedIndex = 0;
            }
        }

        private Dictionary<int, ProfileProperty> GetProfileProperties(int portalID)
        {
            Dictionary<int, ProfileProperty> propertyList = new Dictionary<int, ProfileProperty>();

            // Add in the "standard" UserInfo fields that are not stored as profile properties

            propertyList.Add(-7, new ProfileProperty(-7, "Username", UserVisibilityMode.AllUsers));
            propertyList.Add(-6, new ProfileProperty(-6, "DisplayName", UserVisibilityMode.AllUsers));
            propertyList.Add(-5, new ProfileProperty(-5, "Email", UserVisibilityMode.AdminOnly));
            if (IsAdministrator) propertyList.Add(-4, new ProfileProperty(-4, "Password", UserVisibilityMode.AdminOnly));
            propertyList.Add(-3, new ProfileProperty(-3, "LastActivityDate", UserVisibilityMode.AllUsers));
            propertyList.Add(-2, new ProfileProperty(-2, "LastLoginDate", UserVisibilityMode.AllUsers));
            propertyList.Add(-1, new ProfileProperty(-1, "CreatedOnDate", UserVisibilityMode.AllUsers));

            foreach (ProfilePropertyDefinition ppd in ProfileController.GetPropertyDefinitionsByPortal(portalID))
            {
                propertyList.Add(ppd.PropertyDefinitionId, new ProfileProperty(ppd));
            }

            return propertyList;
        }

        private void BindProfileProperties()
        {
            grdProfileProperties.DataSource = ProfileProperties.Values;
            grdProfileProperties.DataKeyField = "PropertyDefinitionID";
            grdProfileProperties.DataBind();
        }

        private Dictionary<int, ProfileProperty> GetSelectedProfileProperties()
        {
            Dictionary<int, ProfileProperty> selectedProfileProperties = new Dictionary<int, ProfileProperty>();
            foreach (DataGridItem dgi in grdProfileProperties.Items)
            {
                if (dgi.ItemType == ListItemType.Item || dgi.ItemType == ListItemType.AlternatingItem)
                {
                    CheckBox cbSelected = (CheckBox)dgi.Cells[0].Controls[0];
                    int propertyDefinitionID = Convert.ToInt32(grdProfileProperties.DataKeys[dgi.ItemIndex]);
                    ProfileProperty profileProperty = ProfileProperties[propertyDefinitionID];
                    profileProperty.Selected = cbSelected.Checked;
                    if (cbSelected.Checked) selectedProfileProperties.Add(propertyDefinitionID, profileProperty);
                }
            }
            return selectedProfileProperties;
        }

        private void ShowModuleMessage(string msg, ModuleMessage.ModuleMessageType messageType )
        {
            phModuleMessage.Visible = true;
            ModuleMessage moduleMessage = DotNetNuke.UI.Skins.Skin.GetModuleMessageControl(null, msg, messageType, null);
            phModuleMessage.Controls.Add(moduleMessage);
        }



#endregion


    }
}